// Copyright 2019 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

// Package forbiddenmethod defines an suite of Analyzers that
// detects correct setting of timestamps when unmarshaling table
// descriptors.
package forbiddenmethod

import "golang.org/x/tools/go/analysis"

var descriptorMarshalOptions = Options{
	PassName: "descriptormarshal",
	Doc:      `check for correct unmarshaling of descpb descriptors`,
	Package:  "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb",
	Type:     "Descriptor",
	Method:   "^Get(Table|Database|Type|Schema)$",
	Hint:     "see descpb.FromDescriptorWithMVCCTimestamp()",
}

var grpcClientConnCloseOptions = Options{
	PassName: "grpcconnclose",
	Doc:      `prevent calls to (grpc.ClientConn).Close`,
	Package:  "google.golang.org/grpc",
	Type:     "ClientConn",
	Method:   "Close",
	Hint: "must elide the call to Close() if the ClientConn is from an *rpc.Context. " +
		"Do `grpcConn.Close() // nolint:grpcconnclose` when the conn does not come from an rpc.Context.",
}

var grpcStatusWithDetailsOptions = Options{
	PassName: "grpcstatuswithdetails",
	Doc:      `prevent calls to (status.Status).WithDetails`,
	Package:  "google.golang.org/grpc/internal/status",
	Type:     "Status",
	Method:   "WithDetails",
	Hint:     "does not work with gogoproto-generated Protobufs.",
}

var errGroupGo = Options{
	PassName: "errgroupgo",
	Doc:      `prevent calls to (*errgroup.Group).Go`,
	Package:  "golang.org/x/sync/errgroup",
	Type:     "Group",
	Method:   "Go",
	Hint:     "Use (*ctxgroup.Group).Go instead",
}

// DescriptorMarshalAnalyzer checks for correct unmarshaling of descpb
// descriptors by disallowing calls to (descpb.Descriptor).GetTable() et al.
var DescriptorMarshalAnalyzer = Analyzer(descriptorMarshalOptions)

// GRPCClientConnCloseAnalyzer checks for calls to (*grpc.ClientConn).Close.
// We mostly pull these objects from *rpc.Context, which manages their lifecycle.
// Errant calls to Close() disrupt the connection for all users.
var GRPCClientConnCloseAnalyzer = Analyzer(grpcClientConnCloseOptions)

// ErrGroupGoAnalyzer checks for calls to (*errgroup.Group).Go. We should use
// (*ctxgroup.Group).Go instead.
var ErrGroupGoAnalyzer = Analyzer(errGroupGo)

// GRPCStatusWithDetailsAnalyzer checks that we don't use Status.WithDetails(),
// since it does not support Protobufs generated by gogoproto. This is
// because it uses an Any field to store details, with a reference to the
// type, but gogoproto types are not registered with the standard Protobuf
// type registry and are therefore unknown to the unmarshaler.
//
// One could instead use a GoGo-compatible version of Status from
// github.com/gogo/status, but we probably want to move away from gogoproto.
//
// See also: https://github.com/cockroachdb/errors/issues/63
var GRPCStatusWithDetailsAnalyzer = Analyzer(grpcStatusWithDetailsOptions)

// Analyzers are all of the Analyzers defined in this package.
var Analyzers = []*analysis.Analyzer{
	// NOTE(ricky): The analyzers in this list each have a corresponding
	// wrapper package (for example, DescriptorMarshalAnalyzer is exposed as
	// pkg/testutils/lint/passes/descriptormarshal.Analyzer). This is done
	// for compatibility w/ the Bazel build -- the wrapper packages are
	// consumed in :crdb_nogo in the top-level BUILD.bazel.
	DescriptorMarshalAnalyzer,
	GRPCClientConnCloseAnalyzer,
	GRPCStatusWithDetailsAnalyzer,
	// TODO(tbg): fix the lint infractions this finds and
	// enable.
	//
	// ErrGroupGoAnalyzer,
	// NakedGoAnalyzer,
}

var _ = ErrGroupGoAnalyzer
var _ = NakedGoAnalyzer
